﻿using System;
using System.Diagnostics;

namespace Tables
{
    class StringTable : IDisposable
    {
        public StringTable()
            : this(100)
        { }
        public StringTable(int maxStrings)
        {
            _curId = 0;
            _maxStrings = maxStrings;
            _offset = new int[maxStrings];
            _strBuf = new StringBuffer(maxStrings);
        }
        /// <summary>
        /// Adds with out checking for duplicates
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public int ForceAdd(string str, int len)
        {
            // check if there is enough room in the array
            if (_curId == _maxStrings || !_strBuf.WillFit(len))
            {
                return idNotFound;
            }
            // point to the place where the string is stored
            _offset[_curId] = _strBuf.GetOffset();
            _strBuf.Add(str);
            // add mapping into hash table
            _htab.Add(str, _curId);
            ++_curId;
            return _curId - 1;
        }
        /// <summary>
        /// Adds with out checking for duplicates
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public int ForceAdd(string str)
        {
            return ForceAdd(str, str.Length);
        }
        /// <summary>
        /// Translates a string into an id value
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public int Find(string str)
        {
            // get short list from hash table
            List list = _htab.Find(str);
            // iterate list
            for (Link pLink = list.GetHead();
                list.Count != 0;
                pLink = pLink.Next())
            {
                int id = pLink.Id();
                int offset = _offset[id];
                if (_strBuf.IsEqual(offset, str))
                    return id;
            }
            return idNotFound;
        }
        /// <summary>
        /// uses an id value and returns the string for it
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public string GetString(int id)
        {
            // map integer to string, must be valid id
            Debug.Assert(id >= 0);
            Debug.Assert(id < _curId);
            int offset = _offset[id];
            return _strBuf.GetString(offset);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    //disposed managed resource

                }
                // release unmanaged resource
            }
            _disposed = true;

            // if available, call to base class
            // base.Dispose(disposing);
        }

        private HTable _htab = new HTable();
        private int[] _offset;
        private int _curId;
        private StringBuffer _strBuf;
        private bool _disposed = false;
        private const int idNotFound = -1;
        private int _maxStrings;
    }
}
